{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4b61fc87",
   "metadata": {},
   "source": [
    "# 哈密顿量的构造\n",
    "*Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.*"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "52532fe2",
   "metadata": {},
   "source": [
    "## 概览\n",
    "\n",
    "在本教程中，我们将展示如何使用 Paddle Quantum 的 `qchem` 模块通过化学分子式来构造适用于量子计算机的哈密顿量。我们将一步一步地学习如何从一个分子结构构造二次量子化的哈密顿量，以及如何将它转换成一组泡利矩阵。  \n",
    "\n",
    "哈密顿量是一个与物理系统总能量有关的物理量。一般来说，它可以表示为  \n",
    "\n",
    "$$\n",
    "\\hat{H}=\\hat{T}+\\hat{V},\\tag{1}\n",
    "$$\n",
    "\n",
    "其中 $\\hat{T}$ 代表动能，$\\hat{V}$ 代表势能。哈密顿量在变分量子算法中有着重要应用，如比[变分量子本征求解器](./VQE_CN.ipynb) 以及 [利用 Product Formula 模拟时间演化](./HamiltonianSimulation_CN.ipynb)。\n",
    "\n",
    "当我们用量子力学来解决化学问题时，需要写出一个哈密顿量来描述这个问题涉及的化学系统。我们可以根据这个哈密顿量计算该系统的基态和激发态，并利用这些信息进一步探索量子系统的所有物理性质。涉及电子结构问题的哈密顿量可以写成如下形式：\n",
    "\n",
    "$$\n",
    "\\hat{H}=\\sum_{i=1}^N\\left(-\\frac{1}{2}\\nabla_{x_i}^2\\right)+\\sum_{i=1}^N\\sum_{j< i}\\frac{1}{|x_i-x_j|}-\\sum_{i=1}^N\\sum_{I=1}^M\\frac{Z_I}{|x_i-R_I|},\\tag{2}\n",
    "$$\n",
    "\n",
    "该公式使用了[原子单位](https://en.wikipedia.org/wiki/Hartree_atomic_units)。该公式包含了 $N$ 个电子和 $M$ 个原子核，其中 $x_i$ 是第 $i$ 个电子的位置，$R_I$ 是第 $I$ 个原子核的位置。\n",
    "\n",
    "本教程分为四部分，首先我们先来讨论如何使用 `qchem` 模块构造一个分子。之后，我们将简要描述如何通过调用外部量子化学工具来计算\n",
    "[Hartree Fock](https://en.wikipedia.org/wiki/Hartree%E2%80%93Fock_method)\n",
    "单粒子轨道。接下来，我们展示如何得到二次量子化的哈密顿量。最后，我们将描述如何将费米子的哈密顿量 (Fermionic Hamiltonian) 转化为适用于量子计算机的泡利字符串 (Pauli strings)。  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3160994c",
   "metadata": {},
   "source": [
    "## 水分子的结构\n",
    "\n",
    "在该部分，我们将展示如何从水的分子式和原子坐标构造出水分子。\n",
    "\n",
    "![h2o.png](figures/buildingmolecule-fig-h2o.png)\n",
    "\n",
    "在量桨中，我们将分子写成一个列表的形式，第一个元素是原子符号，第二个元素是它的位置 (Cartesian coordinate)。因此，用于表述分子的列表是由原子列表组成的。\n",
    "\n",
    "**注意：关于环境设置，请参考 [README_CN.md](https://github.com/PaddlePaddle/Quantum/blob/master/README_CN.md).**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e6787ece",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Eliminate noisy python warnings\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "import logging\n",
    "logging.basicConfig(level=logging.INFO)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "94b2032c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# in Angstrom\n",
    "h2o_coords = [(\"H\", [-0.02111417,0.8350417,1.47688078]),  # H 代表着水分子中的氢元素\n",
    "                        (\"O\", [0.0, 0.0, 0.0]),                     # O 代表着水分子中的氧元素\n",
    "                        (\"H\", [-0.00201087,0.45191737,-0.27300254])]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "e996795a",
   "metadata": {},
   "source": [
    "## Hartree Fock 轨道的计算\n",
    "\n",
    "Hartree Fock 方法使用 [Slater 行列式](https://en.wikipedia.org/wiki/Slater_determinant)来表示 $N$ 电子波函数。它可以为我们提供一套单粒子轨道，这些轨道通常被作为其他量子化学方法的输入。 \n",
    "\n",
    "量桨当前的量子化学引擎是 PySCF [1]，未来我们也将支持 psi4 等更多的量子化学工具包（注：PySCF 目前仅支持 Mac 和 Linux 平台）。我们可以使用 `qchem` 模块提供的 `PySCFDriver` 类来进行 Hartree Fock 计算，它以分子结构、分子总电荷数和自旋多重度为主要输入，我们还可以通过在 `basis` 参数中指定不同的 [basis set](https://en.wikipedia.org/wiki/Basis_set_(chemistry)) 来控制 Hartree Fock 计算的精度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "29945676",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:root:\n",
      "#######################################\n",
      "SCF Calculation (Classical)\n",
      "#######################################\n",
      "INFO:root:Basis: sto-3g\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "converged SCF energy = -73.9677038774737\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:root:SCF energy: -73.96770.\n"
     ]
    }
   ],
   "source": [
    "from paddle_quantum.qchem import PySCFDriver\n",
    "\n",
    "driver = PySCFDriver()\n",
    "driver.load_molecule(\n",
    "    atom=h2o_coords,         # H2O 分子几何结构\n",
    "    basis=\"sto-3g\",          # 量子化学计算基组（basis set）\n",
    "    multiplicity=1,          # 分子的自旋多重度，因为水分子总自旋为S=0，所以自旋多重度2S+1=1\n",
    "    charge=0,                 # 分子电荷，水分子是中性分子，总电荷为0\n",
    "    unit=\"Angstrom\"\n",
    ")\n",
    "driver.run_scf()             # 进行 Hartree Fock 计算"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "973af7d1",
   "metadata": {},
   "source": [
    "## 哈密顿量的二次量子化形式\n",
    "\n",
    "当我们研究电子系统时，通常会将哈密顿量写成[二次量子化](https://en.wikipedia.org/wiki/Second_quantization)的形式\n",
    "\n",
    "$$\n",
    "\\hat{H}=\\sum_{p,q}h_{pq}\\hat{c}^{\\dagger}_p\\hat{c}_q+\\frac{1}{2}\\sum_{p,q,r,s}v_{pqrs}\\hat{c}^{\\dagger}_p\\hat{c}^{\\dagger}_q\\hat{c}_r\\hat{c}_s,\\tag{3}$$\n",
    "\n",
    "其中 $p$, $q$, $r$ 和 $s$ 是 Hartree Fock 轨道，$\\hat{c}^{\\dagger}_p$ 和 $\\hat{c}_q$ 分别是生成算子 (creation operation) 和湮灭算子 (annihilation operation)。系数 $h_{pq}$ 和 $v_{pqrs}$ 分别是单体积分 (one-body integrations) 和双体积分 (two-body integrations)，该信息可以用如下的方式从 `PySCFDriver` 中计算出来。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a9a906ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-3.2911e+01  5.5623e-01  2.8755e-01 -5.1653e-15 -7.4568e-02 -9.4552e-02 -2.8670e-01]\n",
      " [ 5.5623e-01 -8.0729e+00 -4.0904e-02  1.5532e-15  1.7890e-01  3.5048e-01  1.3460e+00]\n",
      " [ 2.8755e-01 -4.0904e-02 -7.3355e+00  6.8611e-16  4.1911e-01  5.2109e-01 -7.0928e-01]\n",
      " [-5.1650e-15  1.5617e-15  6.7472e-16 -7.5108e+00  5.4096e-16  1.7947e-15  4.5448e-16]\n",
      " [-7.4568e-02  1.7890e-01  4.1911e-01  5.3561e-16 -5.7849e+00  2.0887e+00 -1.2427e-01]\n",
      " [-9.4552e-02  3.5048e-01  5.2109e-01  1.8235e-15  2.0887e+00 -5.0803e+00 -1.3967e-02]\n",
      " [-2.8670e-01  1.3460e+00 -7.0928e-01  4.8475e-16 -1.2427e-01 -1.3967e-02 -5.0218e+00]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np \n",
    "np.set_printoptions(precision=4, linewidth=150)\n",
    "\n",
    "hpq = driver.get_onebody_tensor(\"int1e_kin\") + driver.get_onebody_tensor(\"int1e_nuc\")\n",
    "vpqrs = driver.get_twobody_tensor()\n",
    "assert np.shape(hpq)==(7, 7)             # H2O 分子在STO-3G基组下的轨道数量为7个\n",
    "assert np.shape(vpqrs)==(7, 7, 7, 7)\n",
    "\n",
    "print(hpq)\n",
    "# print(vpqrs)  # vpqrs张量规模较大，为使输出更简洁，我们默认将这一行注释，感兴趣的用户可以将这个张量打印出来"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "de4f1bf2",
   "metadata": {},
   "source": [
    "大多数情况下，我们并不需要把这些积分信息手动的提取出来，*qchem* 模块已经将该过程封装在 `Molecule` 类中，我们可以直接从它里面得到水分子的哈密顿量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "069cfcd5",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:root:\n",
      "#######################################\n",
      "SCF Calculation (Classical)\n",
      "#######################################\n",
      "INFO:root:Basis: sto-3g\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "converged SCF energy = -73.9677038774737\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:root:SCF energy: -73.96770.\n"
     ]
    }
   ],
   "source": [
    "# 构建 H2O 的 `Molecule` 实例\n",
    "from paddle_quantum.qchem import Molecule\n",
    "\n",
    "mol = Molecule(\n",
    "    geometry=h2o_coords,\n",
    "    basis=\"sto-3g\",\n",
    "    driver=PySCFDriver()\n",
    ")\n",
    "\n",
    "\n",
    "H_of_water = mol.get_molecular_hamiltonian()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "e71ea17b",
   "metadata": {},
   "source": [
    "由于量子计算中允许的操作是基于泡利算符$\\hat{\\sigma}_x$、$\\hat{\\sigma}_y$、$\\hat{\\sigma}_z$的，因此，我们需要将上式中的哈密顿量（二次量子化形式）变换成量子比特算符 (qubit operator)，这可以通过[Jordan-Wigner 变换](https://en.wikipedia.org/wiki/Jordan%E2%80%93Wigner_transformation)实现。在*qchem*中，这一功能已经被集成到 `get_molecular_hamiltonian` 方法中了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7a831c80",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 2110 terms in H2O Hamiltonian in total.\n",
      "The first 10 terms are \n",
      " -44.808115297466266 I\n",
      "12.537584025014317 Z0\n",
      "12.537584025014313 Z1\n",
      "1.8115178684479893 Z2\n",
      "1.8115178684479893 Z3\n",
      "1.4546840922727915 Z4\n",
      "1.4546840922727915 Z5\n",
      "1.4299903414012243 Z6\n",
      "1.429990341401224 Z7\n",
      "1.0849294605602529 Z8\n"
     ]
    }
   ],
   "source": [
    "print('There are', H_of_water.n_terms, 'terms in H2O Hamiltonian in total.')\n",
    "print('The first 10 terms are \\n', H_of_water[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5af604d",
   "metadata": {},
   "source": [
    "现在，我们知道了如何从分子结构构造出相应的哈密顿量，接下来不妨去看一看如何使用[变分量子本征求解器](./VQE_CN.ipynb) (VQE)去计算氢分子的基态能量。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "d7417802",
   "metadata": {},
   "source": [
    "---\n",
    "## 参考文献\n",
    "\n",
    "[1] [PySCF: Python-based Simulations of Chemistry Framework](https://pyscf.org/)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "modellib",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.15"
  },
  "vscode": {
   "interpreter": {
    "hash": "8f24120f890011f53feb4ed62c47961d8565ec1de8b7cb23548c15bd6da8f2d2"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
